package org.convallaria.system.biz.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.system.biz.service.CacheOptimizationService;
import org.convallaria.system.biz.service.SecurityConfigService;
import org.convallaria.system.biz.service.sys.SysUserService;
import org.convallaria.system.biz.service.sys.SysRoleService;
import org.convallaria.system.biz.service.sys.SysMenuService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 缓存优化服务实现
 * 
 * @author convallaria
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CacheOptimizationServiceImpl implements CacheOptimizationService {

    private final RedisTemplate<String, String> redisTemplate;
    private final SecurityConfigService securityConfigService;
    private final SysUserService sysUserService;
    private final SysRoleService sysRoleService;
    private final SysMenuService sysMenuService;

    private static final String CACHE_STATS_KEY = "cache:stats";
    private static final String CACHE_HIT_KEY = "cache:hit";
    private static final String CACHE_MISS_KEY = "cache:miss";

    @Override
    @Async
    public void warmupCache() {
        log.info("开始缓存预热...");
        
        try {
            // 预热各种缓存
            warmupUserCache();
            warmupPermissionCache();
            warmupConfigCache();
            
            log.info("缓存预热完成");
        } catch (Exception e) {
            log.error("缓存预热失败", e);
        }
    }

    @Override
    @Async
    public void warmupUserCache() {
        try {
            log.info("预热用户相关缓存...");
            
            // 预热用户配置缓存
            securityConfigService.getSecurityConfig();
            securityConfigService.getPasswordPolicyConfig();
            securityConfigService.getLoginLimitConfig();
            securityConfigService.getTokenConfig();
            
            log.info("用户相关缓存预热完成");
        } catch (Exception e) {
            log.error("预热用户缓存失败", e);
        }
    }

    @Override
    @Async
    public void warmupPermissionCache() {
        try {
            log.info("预热权限相关缓存...");
            
            // 预热权限相关缓存
            // 这里可以预热角色、菜单、权限等常用数据
            
            log.info("权限相关缓存预热完成");
        } catch (Exception e) {
            log.error("预热权限缓存失败", e);
        }
    }

    @Override
    @Async
    public void warmupConfigCache() {
        try {
            log.info("预热配置相关缓存...");
            
            // 预热系统配置缓存
            securityConfigService.getAllConfigs();
            
            log.info("配置相关缓存预热完成");
        } catch (Exception e) {
            log.error("预热配置缓存失败", e);
        }
    }

    @Override
    @Scheduled(fixedRate = 1800000) // 每30分钟执行一次
    public void cleanExpiredCache() {
        try {
            log.info("开始清理过期缓存...");
            
            // 获取所有缓存键
            String pattern = "*";
            Set<String> keys = redisTemplate.keys(pattern);
            
            if (keys != null) {
                int cleanedCount = 0;
                for (String key : keys) {
                    // 检查键是否过期
                    if (redisTemplate.getExpire(key) == -1) {
                        // 设置默认过期时间
                        redisTemplate.expire(key, Duration.ofHours(24));
                        cleanedCount++;
                    }
                }
                
                log.info("清理过期缓存完成，处理了 {} 个键", cleanedCount);
            }
        } catch (Exception e) {
            log.error("清理过期缓存失败", e);
        }
    }

    @Override
    public CacheStatistics getCacheStatistics() {
        try {
            // 获取缓存统计信息
            long totalKeys = getTotalKeys();
            long hitCount = getCacheHitCount();
            long missCount = getCacheMissCount();
            double hitRate = calculateHitRate(hitCount, missCount);
            long memoryUsage = getMemoryUsage();
            long maxMemory = getMaxMemory();
            List<CacheKeyInfo> topKeys = getTopKeys();

            return new CacheStatistics(
                totalKeys, hitCount, missCount, hitRate, 
                memoryUsage, maxMemory, topKeys
            );
        } catch (Exception e) {
            log.error("获取缓存统计信息失败", e);
            return new CacheStatistics(0L, 0L, 0L, 0.0, 0L, 0L, new ArrayList<>());
        }
    }

    @Override
    public void optimizeCacheConfig() {
        try {
            log.info("开始优化缓存配置...");
            
            // 优化缓存配置
            // 1. 调整过期时间
            optimizeExpirationTimes();
            
            // 2. 清理无用缓存
            cleanUnusedCache();
            
            // 3. 调整内存使用
            optimizeMemoryUsage();
            
            log.info("缓存配置优化完成");
        } catch (Exception e) {
            log.error("优化缓存配置失败", e);
        }
    }

    /**
     * 获取总键数
     */
    private long getTotalKeys() {
        try {
            Set<String> keys = redisTemplate.keys("*");
            return keys != null ? keys.size() : 0L;
        } catch (Exception e) {
            log.error("获取总键数失败", e);
            return 0L;
        }
    }

    /**
     * 获取缓存命中次数
     */
    private long getCacheHitCount() {
        try {
            String hitCount = redisTemplate.opsForValue().get(CACHE_HIT_KEY);
            return hitCount != null ? Long.parseLong(hitCount) : 0L;
        } catch (Exception e) {
            log.error("获取缓存命中次数失败", e);
            return 0L;
        }
    }

    /**
     * 获取缓存未命中次数
     */
    private long getCacheMissCount() {
        try {
            String missCount = redisTemplate.opsForValue().get(CACHE_MISS_KEY);
            return missCount != null ? Long.parseLong(missCount) : 0L;
        } catch (Exception e) {
            log.error("获取缓存未命中次数失败", e);
            return 0L;
        }
    }

    /**
     * 计算命中率
     */
    private double calculateHitRate(long hitCount, long missCount) {
        long total = hitCount + missCount;
        return total > 0 ? (double) hitCount / total : 0.0;
    }

    /**
     * 获取内存使用量
     */
    private long getMemoryUsage() {
        try {
            // 简化实现，实际应该从Redis INFO命令获取
            return 0L;
        } catch (Exception e) {
            log.error("获取内存使用量失败", e);
            return 0L;
        }
    }

    /**
     * 获取最大内存
     */
    private long getMaxMemory() {
        try {
            // 简化实现，实际应该从Redis INFO命令获取
            return 0L;
        } catch (Exception e) {
            log.error("获取最大内存失败", e);
            return 0L;
        }
    }

    /**
     * 获取热门键
     */
    private List<CacheKeyInfo> getTopKeys() {
        try {
            // 简化实现，实际应该分析键的访问频率
            List<CacheKeyInfo> topKeys = new ArrayList<>();
            topKeys.add(new CacheKeyInfo("user:1", "user", 100L, 1024L, 3600L));
            topKeys.add(new CacheKeyInfo("role:admin", "role", 80L, 512L, 3600L));
            return topKeys;
        } catch (Exception e) {
            log.error("获取热门键失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 优化过期时间
     */
    private void optimizeExpirationTimes() {
        try {
            // 根据访问频率调整过期时间
            // 高频访问的键设置更长的过期时间
            // 低频访问的键设置较短的过期时间
            log.info("优化过期时间配置");
        } catch (Exception e) {
            log.error("优化过期时间失败", e);
        }
    }

    /**
     * 清理无用缓存
     */
    private void cleanUnusedCache() {
        try {
            // 清理长时间未访问的缓存
            log.info("清理无用缓存");
        } catch (Exception e) {
            log.error("清理无用缓存失败", e);
        }
    }

    /**
     * 优化内存使用
     */
    private void optimizeMemoryUsage() {
        try {
            // 优化内存使用策略
            log.info("优化内存使用配置");
        } catch (Exception e) {
            log.error("优化内存使用失败", e);
        }
    }
}
